home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-04-29 | 17.6 KB | 543 lines | [TEXT/CWIE] |
- //================================================================================
- // Greg Anderson
- // db+
- //
- // Cursor to a data record
- // 18 May 1994
- // 31 Dec 1994
- //================================================================================
- #pragma once
-
- #include "DBProperty.h"
-
- #include "DatabaseDocument.h"
- #include "DataRecord.h"
- #include "Transaction.h"
-
- #include "Exceptions.h"
-
- #define INHERITED TDBRecord
-
- //--------------------------------------------------------------------------------
- // TDBProperty::~TDBProperty
- //--------------------------------------------------------------------------------
- TDBProperty::~TDBProperty()
- {
- } // TDBProperty::~TDBProperty
-
- //--------------------------------------------------------------------------------
- // TDBProperty::CompareSortKeys
- //--------------------------------------------------------------------------------
- CompareEnumeration TDBProperty::CompareSortKeys(TTransaction* t, AConst<TDBRecord> secondObject) const
- {
- AConst<TDBProperty> dataRecord = secondObject->DBPropertyCursor();
-
- return this->DetermineCompareEnumeration(this->PropertyID(t), dataRecord->PropertyID(t));
- } // TDBProperty::CompareSortKeys
-
- //--------------------------------------------------------------------------------
- // TDBProperty::GetDataType
- //--------------------------------------------------------------------------------
- long TDBProperty::GetDataType(TTransaction* t) const
- {
- long theDataType = kNullType;
-
- switch(this->GetEncodedDataType(t))
- {
- //
- // •To do: Have a table of well-known data types,
- // and do a lookup
- //
- case kEncodedNullType:
- theDataType = kNullType;
- break;
-
- case kEncodedSmallStringType:
- theDataType = kStringType;
- break;
-
- //
- // •To do: Store these types when the properties/elements
- // are stored in the property record, then remove this
- // special-case code and use case kEncodedTypedStructure instead.
- //
- case kSetOfProperties:
- theDataType = kRecordType;
- break;
-
- case kSetOfElements:
- theDataType = kRecordType;
- break;
-
- case kEncodedTypedStructure:
- default:
- theDataType = this->GetStoredDataType(t);
- break;
-
- }
-
- return theDataType;
- } // TDBProperty::GetDataType
-
- //--------------------------------------------------------------------------------
- // TDBProperty::GetDataLength
- //--------------------------------------------------------------------------------
- long TDBProperty::GetDataLength(TTransaction* t) const
- {
- long theDataLength = 0;
-
- switch(this->GetEncodedDataType(t))
- {
- case kEncodedNullType:
- theDataLength = 0;
- break;
-
- case kSetOfProperties:
- case kSetOfElements:
- FailErr(eWrongDataType);
- break;
-
- case kEncodedSmallStringType:
- case kEncodedTypedStructure:
- {
- if(this->OwnsExternalData(t) == false)
- {
- theDataLength = this->GetInternalDataLength(t);
- }
- else
- {
- //
- // Ask external data record how much data it holds
- //
- AConst<TDataRecord> externalData = this->ExternalData(t);
- Require(externalData.Exists());
- theDataLength = externalData->GetDataLength(t);
- }
- break;
- }
- }
-
- return theDataLength;
- } // TDBProperty::GetDataLength
-
- //--------------------------------------------------------------------------------
- // TDBProperty::GetLongData
- //--------------------------------------------------------------------------------
- long TDBProperty::GetLongData(TTransaction* t) const
- {
- Require(this->GetDataType(t) == kLongType);
- return this->GetRecordData(t, kFirstDataWord);
- } // TDBProperty::GetLongData
-
- //--------------------------------------------------------------------------------
- // TDBProperty::GetTypedData
- //--------------------------------------------------------------------------------
- void TDBProperty::GetTypedData(TTransaction* t, TAbstractDataReference& data) const
- {
- if(this->OwnsExternalData(t) == false)
- {
- //
- // First, copy the data we're only allowed to access a longword
- // at a time into some other buffer
- //
- long buffer[3];
-
- for(short i=0; i<3; ++i)
- buffer[i] = this->GetRecordData(t, kFirstDataWord+i);
-
- //
- // Next, copy one char at a time from that buffer into the
- // caller's data space.
- //
- long lengthToCopy = (this->GetDataLength(t) < data.MaxLength()) ? this->GetDataLength(t) : data.MaxLength();
- data.CopyFrom(TConstDataReference(this->GetDataType(t), (char*)&buffer[0], lengthToCopy), true);
- }
- else
- {
- //
- // Copy the data from the external data record
- //
- AConst<TDataRecord> externalData = this->ExternalData(t);
- externalData->GetTypedData(t, data);
- }
- } // TDBProperty::GetTypedData
-
- //--------------------------------------------------------------------------------
- // TDBProperty::Compare
- //--------------------------------------------------------------------------------
- CompareEnumeration TDBProperty::Compare(TTransaction* t, const TAbstractDataReference& compareWith) const
- {
- CompareEnumeration compareResult;
-
- if(this->OwnsExternalData(t) == false)
- {
- compareResult = this->CompareRecordData(t, this->GetDataType(t), kFirstDataWord, this->GetDataLength(t), compareWith);
- }
- else
- {
- //
- // We don't need the rest of this method--just these two lines
- //
- TConstDataReference thisDataRef = this->PropertyDataReference(t);
- compareResult = thisDataRef.Compare(compareWith);
- }
-
- return compareResult;
- } // TDBProperty::Compare
-
- //--------------------------------------------------------------------------------
- // TDBProperty::Compare
- //--------------------------------------------------------------------------------
- CompareEnumeration TDBProperty::Compare(TTransaction* t, AConst<TDBProperty> compareWith) const
- {
- return this->Compare(t, compareWith->PropertyDataReference(t));
- } // TDBProperty::Compare
-
- //--------------------------------------------------------------------------------
- // TDBProperty::Contains
- //--------------------------------------------------------------------------------
- Boolean TDBProperty::Contains(TTransaction* t, const TAbstractDataReference& searchFor) const
- {
- Boolean doesContain = false;
-
- if(this->OwnsExternalData(t) == false)
- {
- doesContain = this->RecordDataContains(t, this->GetDataType(t), kFirstDataWord, this->GetDataLength(t), searchFor);
- }
- else
- {
- //
- // We don't need the rest of this method--just these two lines
- //
- TConstDataReference thisDataRef = this->PropertyDataReference(t);
- doesContain = thisDataRef.Contains(searchFor);
- }
-
- return doesContain;
- } // TDBProperty::Contains
-
- //--------------------------------------------------------------------------------
- // TDBProperty::Contains
- //--------------------------------------------------------------------------------
- Boolean TDBProperty::Contains(TTransaction* t, AConst<TDBProperty> compareWith) const
- {
- return this->Contains(t, compareWith->PropertyDataReference(t));
- } // TDBProperty::Contains
-
- //--------------------------------------------------------------------------------
- // TDBProperty::FreeOwnedData
- //--------------------------------------------------------------------------------
- void TDBProperty::FreeOwnedData(TTransaction* t)
- {
- //
- // We only need to worry about freeing owned external
- // data; elements and properties will be freed up by
- // INHERITED::FreeOwnedData.
- //
- if(this->OwnsExternalData(t))
- {
- //
- // Free our owned external data
- //
- AnUpdate<TDataRecord> externalData = this->UpdateExternalData(t);
- if(externalData.Exists())
- externalData->ReleaseData(t);
- else
- ASSERT(false);
- this->SetOwnsExternalData(t, false);
- }
-
- INHERITED::FreeOwnedData(t);
- } // TDBProperty::FreeOwnedData
-
- //--------------------------------------------------------------------------------
- // TDBProperty::InitializeNewRecord
- //--------------------------------------------------------------------------------
- void TDBProperty::InitializeNewRecord(TTransaction* t)
- {
- TDBRecord::InitializeNewRecord(t);
-
- this->SetRecordFlags(t, kInitialDataRecordFlags);
- this->SetPropertyID(t, 0);
- this->ChangeRecordData(t, kFirstDataWord, 0);
- this->ChangeRecordData(t, kSecondDataWord, 0);
- this->ChangeRecordData(t, kThirdDataWord, 0);
- } // TDBProperty::InitializeNewRecord
-
- //--------------------------------------------------------------------------------
- // TDBProperty::MakeEmpty
- //--------------------------------------------------------------------------------
- void TDBProperty::MakeEmpty(TTransaction* t)
- {
- this->FreeOwnedData(t);
- this->SetEncodedDataType(t, kEncodedNullType);
- this->SetInternalDataLength(t, 0);
- this->ChangeRecordData(t, kFirstDataWord, 0);
- this->ChangeRecordData(t, kSecondDataWord, 0);
- this->ChangeRecordData(t, kThirdDataWord, 0);
- this->InformOwnerPropertyValueChanged(t);
- } // TDBProperty::MakeEmpty
-
- //--------------------------------------------------------------------------------
- // TDBProperty::SetLongData
- //--------------------------------------------------------------------------------
- void TDBProperty::SetLongData(TTransaction* t, long newValue)
- {
- this->SetTypedData(t, TConstDataReference(kLongType, (char*)&newValue, sizeof(long)));
- } // TDBProperty::SetLongData
-
- //--------------------------------------------------------------------------------
- // TDBProperty::SetTypedData
- //--------------------------------------------------------------------------------
- void TDBProperty::SetTypedData(TTransaction* t, const TAbstractDataReference& data)
- {
- long dataType = data.DataType();
- long dataLength = data.DataLength();
-
- //
- // •To do: Look for 'dataLength' in a table of well-known
- // types, and set 'maxInternalLength' to 12 if it is found.
- //
- // n.b. kEncodedTypedStructure is the correct encoded type
- // to use for data > 12 bytes in length, even if the type is
- // well-known.
- //
- long encodedDataType = ((dataType == kStringType) ? kEncodedSmallStringType : kEncodedTypedStructure);
- long maxInternalLength = (encodedDataType != kEncodedTypedStructure) ? 12 : 8;
-
- if(dataLength <= maxInternalLength)
- {
- //
- // Free the data that we used to own, if any
- //
- this->FreeOwnedData(t);
-
- //
- // Remember the length of the data and its type
- //
- this->SetInternalDataLength(t, dataLength);
- this->SetEncodedDataType(t, encodedDataType);
-
- //
- // If the data type could not be encoded into
- // 'encodedDataType', then write the data type
- // into the appropriate record in the property
- // data.
- //
- if(encodedDataType == kEncodedTypedStructure)
- this->SetStoredDataType(t, dataType);
-
- //
- // Data pointer and data mask used in copy loop
- //
- long* dataPtr = (long*)data.Data();
- long dataMask[] = { 0, 0xFF000000, 0xFFFF0000, 0xFFFFFF00 };
-
- //
- // Write two or three longwords into the property data
- //
- for(short i=0; i<(maxInternalLength >> 2); ++i)
- {
- //
- // Insure that the internal storage space that is
- // past the end of the internally stored data is
- // always zeroed out.
- //
- if(dataLength <= 0)
- this->ChangeRecordData(t, kFirstDataWord+i, 0);
- else if(dataLength >= 4)
- this->ChangeRecordData(t, kFirstDataWord+i, *dataPtr);
- else
- this->ChangeRecordData(t, kFirstDataWord+i, *dataPtr & dataMask[dataLength]);
-
- ++dataPtr;
- dataLength -= 4;
- }
- }
- else
- {
- //
- // Remember the type of data we're about to save
- //
- this->SetEncodedDataType(t, kEncodedTypedStructure);
- this->SetStoredDataType(t, dataType);
-
- //
- // Allocate and copy data into an external data record.
- // There may already be an external data record here, or we may
- // need to allocate one.
- //
- AnUpdate<TDataRecord> externalData = this->UpdateExternalData(t);
- if(fExternalData.Exists() == false)
- {
- externalData = this->DBDocument()->NewDataRecord(t, dataLength);
- this->SetOwnsExternalData(t, true);
- externalData->SetDataOwner(t, this);
- fExternalData = externalData;
- }
-
- //
- // Save the data into the external object
- //
- externalData->SetTypedData(t, data);
- }
-
- this->InformOwnerPropertyValueChanged(t);
- } // TDBProperty::SetTypedData
-
- //--------------------------------------------------------------------------------
- // TDBProperty::Verify
- //--------------------------------------------------------------------------------
- void TDBProperty::Verify(TTransaction* t, Boolean verifyDeep) const
- {
- if(this->OwnsExternalData(t))
- {
- AConst<TDataRecord> externalData = this->ExternalData(t);
-
- if(externalData.Exists())
- {
- if(externalData->DataOwnerIndex(t) != this->RecordIndex())
- DebugStr("\pProperty's external data does not point back");
- externalData->Verify(t, verifyDeep);
- }
- else
- DebugStr("\pProperty claims to own external data but cannot find it");
- }
-
- INHERITED::Verify(t, verifyDeep);
- } // TDBProperty::Verify
-
- //--------------------------------------------------------------------------------
- // TDBProperty::ExternalData
- //--------------------------------------------------------------------------------
- AConst<TDataRecord> TDBProperty::ExternalData(TTransaction* t) const
- {
- //
- // Check to see if our external data has moved
- // out from under us (as it will durring PrepareToCommit
- // if the external data block needs to change size).
- //
- if((fExternalData.Exists() == true) && ((this->OwnsExternalData(t) == false) || (fExternalData->RecordIndex() != this->GetExternalDataIndex(t))))
- {
- ((TDBProperty*)this)->fExternalData = AConst<TDataRecord>(nil);
- }
-
- //
- // If we don't have a cached reference to our external
- // data, and we do own extrnal data, then look up the
- // external data cursor and cache it.
- //
- if((fExternalData.Exists() == false) && (this->OwnsExternalData(t)))
- {
- ((TDBProperty*)this)->fExternalData = this->GetDataCursor(this->GetExternalDataIndex(t));
- }
-
- return fExternalData;
- } // TDBProperty::ExternalData
-
- //--------------------------------------------------------------------------------
- // TDBProperty::UpdateExternalData
- //--------------------------------------------------------------------------------
- AnUpdate<TDataRecord> TDBProperty::UpdateExternalData(TTransaction* t)
- {
- AnUpdate<TDataRecord> externalData;
-
- AConst<TDataRecord> constExternalData = this->ExternalData(t);
- if(constExternalData.Exists())
- externalData = this->Transaction()->GetDataRecordUpdatePointer(constExternalData);
-
- return externalData;
- } // TDBProperty::UpdateExternalData
-
- //--------------------------------------------------------------------------------
- // TDBProperty::SetExternalDataIndex
- //--------------------------------------------------------------------------------
- void TDBProperty::SetExternalDataIndex(TTransaction* t, long externalDataIndex)
- {
- this->ChangeRecordData(t, kExternalDataIndex, externalDataIndex);
- } // TDBProperty::SetExternalDataIndex
-
- //--------------------------------------------------------------------------------
- // TDBProperty::RecordCanHaveElements
- //--------------------------------------------------------------------------------
- Boolean TDBProperty::RecordCanHaveElements(TTransaction* t) const
- {
- //
- // Properties of type kSetOfElements have elements; all
- // other properties cannot have elements
- //
- return (this->GetEncodedDataType(t) == kSetOfElements);
- } // TDBProperty::RecordCanHaveElements
-
- //--------------------------------------------------------------------------------
- // TDBProperty::RecordCanHaveProperties
- //--------------------------------------------------------------------------------
- Boolean TDBProperty::RecordCanHaveProperties(TTransaction* t) const
- {
- //
- // Properties of type kSetOfProperties have properties; all
- // other properties cannot have properties
- //
- return (this->GetEncodedDataType(t) == kSetOfProperties);
- } // TDBProperty::RecordCanHaveProperties
-
- //--------------------------------------------------------------------------------
- // TDBProperty::RemoveFromTree
- //
- // Properties notify their owner when they are removed from the tree
- //--------------------------------------------------------------------------------
- void TDBProperty::RemoveFromTree(TTransaction* t)
- {
- AConst<TDBRecord> treeOwner = this->TreeOwner(t);
-
- INHERITED::RemoveFromTree(t);
-
- if(treeOwner.Exists())
- {
- (this->Transaction()->GetDBRecordUpdatePointer(treeOwner))->PropertyValueChanged(t, AConst<TDBProperty>(this));
- }
- } // TDBProperty::RemoveFromTree
-
- //--------------------------------------------------------------------------------
- // TDBProperty::InformOwnerPropertyValueChanged
- //
- // This method is called whenever someone sets the value of a property; its main
- // use is for the element record to resort itself if its name property changes.
- //--------------------------------------------------------------------------------
- void TDBProperty::InformOwnerPropertyValueChanged(TTransaction* t) const
- {
- AConst<TDBRecord> treeOwner = this->TreeOwner(t);
-
- if(treeOwner.Exists())
- {
- (this->Transaction()->GetDBRecordUpdatePointer(treeOwner))->PropertyValueChanged(t, AConst<TDBProperty>(this));
- }
- } // TDBProperty::InformOwnerPropertyValueChanged
-
- //--------------------------------------------------------------------------------
- // TDBProperty::PropertyDataReference
- //
- // Private--only used to do comparisons between properties
- //--------------------------------------------------------------------------------
- TConstDataReference TDBProperty::PropertyDataReference(TTransaction* t) const
- {
- if(this->OwnsExternalData(t) == false)
- {
- return this->RecordDataReference(t, this->GetDataType(t), kFirstDataWord, this->GetDataLength(t));
- }
- else
- {
- AConst<TDataRecord> externalData = this->ExternalData(t);
- Require(externalData.Exists());
- return externalData->DataReference(t);
- }
- } // TDBProperty::PropertyDataReference
-
- //--------------------------------------------------------------------------------
- // TDataRecordComparisonObject::TestObject
- //--------------------------------------------------------------------------------
- CompareEnumeration TDataRecordComparisonObject::TestObject(TTransaction* t, AConst<TDBRecord> testObject)
- {
- return TDBRecord::DetermineCompareEnumeration(fSearchKey, testObject->DBPropertyCursor()->PropertyID(t));
- } // TDataRecordComparisonObject::TestObject
-